﻿// When the document loads do everything inside here ...
$(document).ready(function() {

	$('#dialog').jqm();

	initialize();

	// When a link is clicked
	$("a.tab").click(function() {
		activateTab(this);
		return false;
	});

	refreshMarkerPeriod = $('#UpdateInterval option:selected').attr('value');

	// Fill game list
	getGameList();
});

function getGameList() {
	// get Game list
	$.ajax({
		beforeSend: function() {
			onBeforeSendGetGames();
		},
		complete: function() {
			onCompleteGetGames();
		},
		success: function(result) {
		onSuccessGetGames(result);
		},
		url: urlGetGames,
		dataType: "json",
		timeout: 30000
	});
}

function onBeforeSendGetGames() {
}

function onCompleteGetGames() {
}

function onSuccessGetGames(result) {
	$(result).each(function() {
		$('#ChooseGame').append(
			$('<option>').attr('value', this.ID).html(this.Name)
		)
	});

	$('#ChooseGame option:first').attr('selected', 'selected');
	onChooseGameChange();
}

function onChooseGameChange() {
	gameID = Number($('#ChooseGame option:selected').attr('value'));
	firstGetMarkers = true;
	UpdateDataFromServer();
}

function onUpdateIntervalChange() {
	refreshMarkerPeriod = $('#UpdateInterval option:selected').attr('value');
	UpdateDataFromServer();
}

function UpdateDataFromServer() {
	$("#waitMarkerImage").stopTime(null, null);
	LoadMarkers();
}

//Google maps object
var map = null;
var geocoder = null;
var markerToMove = null;
// период обновления списка маркеров
var refreshMarkerPeriod = '5s';
// game to monitor
var gameID = 0;
// First time retrive mark
var firstGetMarkers = true;
// time after request new marker image after time of unsending, sec
var timeToRefreshMarkerImage = 60 * 5;

//Markers array
var gMarkers = new Array();
var searchedMarkers = new Array();
var pointMarker = null;
var loadedTrackArray = new Array();

// class for holding found marker information
function FoundMarker(Name, Address, gMarker, LatLng) {
	this.Name = Name;
	this.Address = Address;
	this.gMarker = gMarker;
	this.LatLng = LatLng;
};

// return marker info
FoundMarker.prototype.GetInfo = function() {
	return '<b>' + this.Name + '</b><br/>' + this.Address + '<br/>' + this.LatLng.toUrlValue();
}

//Initialize google maps control
function initialize() {

	var options = {
		resultList: document.getElementById("searchresultlist"),
		showOnLoad: true,
		onSearchCompleteCallback: function() {
			onMapSearchCompleteCallback();
		},
		onGenerateMarkerHtmlCallback: function(marker, div, result) {
			return onMapGenerateMarkerHtmlCallback(marker, div, result);
		},
		suppressInitialResultSelection: false,
		suppressZoomToBounds: false
	};


	if (GBrowserIsCompatible()) {
		geocoder = new GClientGeocoder();
		map = new GMap2(document.getElementById("map_canvas"), { googleBarOptions: options });
		map.enableGoogleBar();
		map.setCenter(new GLatLng(54.62466, 39.738571), 11);
		map.enableScrollWheelZoom();
		map.addControl(new GMapTypeControl());
		map.addControl(new GLargeMapControl());
		//map.setUIToDefault();

//		var geoXml = new GGeoXml("http://dozor.obuhov.ru/NWSforWeb/game/m/sa/sa/Game1/m.kml");
//		map.addOverlay(geoXml); 

		// resize controls
		resizeControls();

		CreatePointMarket();
	}
	//LoadMarkers();
}

// after search complete
function onMapSearchCompleteCallback() {
	// activate tab
	activateTab($("#SearchMapTab"));
}

// info for searched marker
function onMapGenerateMarkerHtmlCallback(marker, div, result) {
	var info = "<div id='MapGenerateMarker'><b>" + result.title + " </b><br/>"
		+ "Координаты: " + Number(result.lat) + "," + Number(result.lng) + "<br/>"
		+ " <a href='http://www.google.com/maps?f=q&source=s_q&hl=ru&geocode=&q=" + Number(result.lat) + "," + Number(result.lng) + "&ie=UTF8&z=" + map.getZoom() + "' target='_blank'>(ссылка)</a>"
		+ " "
		+ "<a href='" + result.ddUrlToHere + "' target='_blank'>(сюда)</a>"
		+ " - "
		+ "<a href='" + result.ddUrlFromHere + "' target='_blank'>(отсюда)</a>"
		+ "<br/><br/>"
		+ "<div>Переместить в эту точку маркер:<ul>";

	$(gMarkers).each(function() {
		var onclick = "onclick='onMapGeneratedMarkerClick(" + this.Marker.ID + ", " + result.lat + "," + result.lng + ")'";
		info += "<li><a href='#'" + onclick + ">" + this.Marker.Name + "<a></li>";
	});
		
	info += "</ul></div></div>";
	div.innerHTML = info;
	return div;
}

function onMapGeneratedMarkerClick(markerID, lat, lng) {
	// close info window
	map.closeInfoWindow();
	// move marker
	$(gMarkers).each(function() {
		if (this.Marker.ID == Number(markerID)) {
			this.Marker.Latitude = lat;
			this.Marker.Longitude = lng;
			updateMarkerPanel(findMarkerPanel(this.Marker.ID), this.Marker);
			this.setLatLng(new GLatLng(lat, lng));
			return;
		}
	});
	// inform server of new position
	SetNewMarkerPosition(markerID, lat, lng);
	return false;
}

// Resize based off Googles code.
function resizeControls() {

	// get page element
	var leftDiv = document.getElementById("left");
	var mapDiv = document.getElementById("map_canvas");
	var gameentitylistDiv = document.getElementById("gameentitylist");
	var searchresultlistDiv = document.getElementById("searchresultlist");
	var windowHeight = getWindowHeight();

	// get map top offset
	var offsetTop = 0;
	for (var elem = mapDiv; elem; elem = elem.offsetParent) {
		offsetTop += elem.offsetTop;
	}

	// set map and left panel height
	var height = windowHeight - offsetTop - 1;
	if (height >= 0) {
		mapDiv.style.height = height + "px";
		leftDiv.style.height = height + "px";
	}

	// set height gameentitylistDiv
	offsetTop = 0;
	for (var elem = gameentitylistDiv; elem; elem = elem.offsetParent) {
		offsetTop += elem.offsetTop;
	}
	gameentitylistDiv.style.height = windowHeight - offsetTop - 10 + "px";

	// set height searchresultlistDiv
	offsetTop = 0;
	for (var elem = searchresultlistDiv; elem; elem = elem.offsetParent) {
		offsetTop += elem.offsetTop;
	}
	searchresultlistDiv.style.height = windowHeight - offsetTop - 10 + "px";

	// If the map has been created at this point then resize and alter accordingly
	if (map) { map.checkResize(); }
}

// Return the window height
function getWindowHeight() {
	if (window.self && self.innerHeight) {
		return self.innerHeight;
	}
	if (document.documentElement && document.documentElement.clientHeight) {
		return document.documentElement.clientHeight;
	}
	if (document.body && document.body.clientHeight) {
		return windowHeight = document.body.clientHeight;
	}
	return 0;
}

// Return the window width
function getWindowWidth() {
	if (window.self && self.innerWidth) { return self.innerWidth; }
	if (document.documentElement && document.documentElement.clientWidth) {
		return document.documentElement.clientWidth;
	}
	return 0;
}


// activate tab
function activateTab(tab) {
	// switch all tabs off
	$(".active").removeClass("active");

	// switch this tab on
	$(tab).addClass("active");

	// slide all content up
	$(".content").hide();

	// slide this content up
	var content_show = $(tab).attr("title");
	$("#" + content_show).show();

	resizeControls();
}


//Load markers
function LoadMarkers() {
	$.ajax({
		beforeSend: function() {
			onBeforeStartGetMarkers();
		},
		complete: function() {
			onCompleteGetMarkers();
		},
		success: function(result) {
			ProcessMarkers(result);
		},
		url: urlGetMarkers,
		data: { gameID: gameID },
		dataType: "json",
		timeout: 30000
	});
}
// Game marker functions====================================
// onBeforeStartGetMarkers
function onBeforeStartGetMarkers() {
	$("#waitMarkerImage").show();
}

function onCompleteGetMarkers() {
	$("#waitMarkerImage").hide();
	$("#waitMarkerImage").oneTime(refreshMarkerPeriod, function() {
		LoadMarkers();
	});
}

// clear markers
function clearMarkers() {
	$(".gameentitylist ul li").remove();
	return false;
}

function findMarkerListPanel() {
	return $(".gameentitylist ul");
}

function findMarkerPanel(markerID) {
	var item = $("li.#markerID" + markerID);
	if (item.length == 0)
		return null;
	else
		return item;
}

/*
<li id="markerID[XX]">
<div class="markerPanel">
<div class="markerPanelTop">
<div class="markerName">
<a href=""><b>Name</b></a>
<div class="markerMenu">
<>...<>
</div>
</div>

<div>
<div class="markerPanelCenter">
<div class="markerSpeed">
<span id="speedLabel">Скорость:</span><span id="speedParam">Speed</span><span id="speedKMH">км/ч</span>
</div>
					
<div class="markerLatLng">
<span id="latLabel">Lat:</span><span id="latParam">Latitude</span>
<span id="latlngSeparator">,</span>
<span id="lngLabel">Lng:</span><span id="lngParam">Longitude</span>
</div>
					
<div class="markerDelay">
<span id="delayLabel">Обновлено:</span><span id="delayParam">Delay</span>
</div>
</div>
</div>
</li>

*/
function createMarkerPanel(marker) {
	/*
	<li id="markerID[XX]">
	<div class="markerPanel"> */
	$(".gameentitylist ul").append(
			$("<li>").attr("id", "markerID" + marker.ID).addClass("markerPanelLI").append(
				$("<div>").addClass("markerPanel")
			)
		);

	var markerPanel = $("#markerID" + marker.ID + " div.markerPanel");
	/*
	<div class="markerPanelTop">
	<div class="markerName">
	<a href=""><b>Name</b></a>
	<div class="markerMenu">
	<>...<>
	</div>
	</div>
	<div>
	*/
	markerPanel.append(
			$("<div>").addClass("markerPanelTop").append(
				$("<div>").addClass("markerName").append(
					$("<a>").addClass("markerNameRef").attr("href", "").append(
						$("<b>").html(marker.Name)
					)
				).append(
					$("<div>").addClass("markerMenu").append(
						$("<a>").addClass("markerMenuVISIBLE").attr("href", "").html("☼")
						).append(
							$("<a>").addClass("markerMenuUP").attr("href", "").html("↑")
						).append(
							$("<a>").addClass("markerMenuDOWN").attr("href", "").html("↓")
						).append(
							$("<a>").addClass("markerMenuSLIDE").attr("href", "").html("↨")
						)
					)
				)
			).append(
			$("<div>").addClass("markerPanelCenter")
			);

	// attach handlers
	markerPanel.find("a.markerNameRef").live("click", function() {
		return onMarkerNameClick(markerPanel.parent().parent());
	});
	markerPanel.find("a.markerMenuVISIBLE").live("click", function() {
		return onMarkerVisibleClick(marker.ID);
	});
	markerPanel.find("a.markerMenuUP").live("click", function() {
		return onMarkerPanelUp(markerPanel.parent().parent());
	});
	markerPanel.find("a.markerMenuDOWN").live("click", function() {
		return onMarkerPanelDown(markerPanel.parent().parent());
	});
	var markerID = "#markerID" + marker.ID;
	markerPanel.find("a.markerMenuSLIDE").live("click", function() {
		return onMarkerPanelToggle(markerID);
	});

	markerPanel = $("#markerID" + marker.ID + " div.markerPanelCenter");
	/*
	<div class="markerSpeed">
	<span id="speedLabel">Скорость:</span>
	<span id="speedParam">Speed</span>
	<span id="speedKMH">км/ч</span>
	</div> */
	var divSpeed = $("<div>").addClass("markerSpeed").appendTo(markerPanel);
	divSpeed.append(
			$("<span>").attr("id", "speedLabel").html("Скорость:")
		).append(
			$("<span>").attr("id", "speedParam").html(Number(marker.Speed).toFixed(0))
		).append(
			$("<span>").attr("id", "speedKMH").html("км/ч")
		);

	/*
	<div class="markerLatLng">
	<span id="latLabel">Lat:</span><span id="latParam">Latitude</span>
	<span id="latlngSeparator">,</span>
	<span id="lngLabel">Lng:</span><span id="lngParam">Longitude</span>
	</div>*/
	var divLatLng = $("<div>").addClass("markerLatLng").appendTo(markerPanel);
	divLatLng.append(
			$("<span>").attr("id", "latLabel").html("Lat:")
		).append(
			$("<span>").attr("id", "latParam").html(Number(marker.Latitude).toFixed(4))
		).append(
			$("<span>").attr("id", "latlngSeparator").html(",")
		).append(
			$("<span>").attr("id", "lngLabel").html("Lng:")
		).append(
			$("<span>").attr("id", "lngParam").html(Number(marker.Longitude).toFixed(4))
		);

	/*
	<div class="markerDelay">
	<span id="delayLabel">Обновлено:</span><span id="delayParam">Delay</span>
	</div>*/
	var divDelay = $("<div>").addClass("markerDelay").appendTo(markerPanel);
	divDelay.append(
			$("<span>").attr("id", "delayLabel").html("Обновлено:")
		).append(
			$("<span>").attr("id", "delayParam").html(GetLastUpdateStringFromDelay(marker.Delay))
		);
}

function updateMarkerPanel(panel, marker) {
	panel.find("#speedParam").html(Number(marker.Speed).toFixed(0));
	panel.find("#latParam").html(Number(marker.Latitude).toFixed(4));
	panel.find("#lngParam").html(Number(marker.Longitude).toFixed(4));
	panel.find("#delayParam").html(GetLastUpdateStringFromDelay(marker.Delay));
}

function deleteMarkerPanel(markerID) {
	// TODO:
	$("li.#markerID" + markerID).remove();
}


// fill list with markers
function ProcessMarkers(result) {

	// process maps data
	MarkersRecieved(result);

	//clearMarkers();

	// add all markers
	$(result).each(function() {

		var markerPanel = findMarkerPanel(this.ID);
		if (markerPanel == null)
			createMarkerPanel(this);
		else
			updateMarkerPanel(markerPanel, this);

		// TODO: delete unused panels

	});

}

function onMarkerNameClick(element) {
	//alert(element);
	var markerID = element.attr("id");
	$(gMarkers).each(function() {
		if ("markerID" + this.Marker.ID == markerID) {
			map.panTo(this.getLatLng());
			return;
		}
	});
	return false;
}

// move element one item up
function onMarkerVisibleClick(markerID) {
	$(gMarkers).each(function() {
		if (this.Marker.ID == Number(markerID)) {
			if (this.isHidden())
				this.show();
			else
				this.hide();
			return;
		}
	});
	return false;
}

// move element one item up
function onMarkerPanelUp(element) {
	var nextItem = element.prev("li");
	if (nextItem != null)
		nextItem.insertAfter(element);
	return false;
}

// move element one item down
function onMarkerPanelDown(element) {
	var nextItem = element.next("li");
	if (nextItem != null)
		nextItem.insertBefore(element);
	return false;
}

// toggle panel
function onMarkerPanelToggle(idPanel) {
	$(idPanel + " .markerPanelCenter").slideToggle("fast", null);
	return false;
}

// Get delay string
function GetLastUpdateString(dateJSON) {
	var currentTime = new Date();
	var msdateRe = /\/Date\((\d+)\)\//;  // MS JSON date format
	var date = new Date(parseInt(dateJSON.replace(msdateRe, '$1')));
	var ms = currentTime.getTime() - date.getTime();
	var result = "";

	var x = ms / 1000
	seconds = x % 60
	result += seconds.toFixed(0) + "s";
	x /= 60
	minutes = x % 60
	if (minutes > 1)
		result = "" + minutes.toFixed(0) + "m " + result;
	x /= 60
	hours = x % 24
	if (hours > 1)
		result = "" + hours.toFixed(0) + "h " + result;
	x /= 24
	days = x
	if (days > 1)
		result = "" + days.toFixed(0) + "d " + result;

	return result;
}

// Get delay string from seconds
function GetLastUpdateStringFromDelay(delay) {
	var ms = parseInt(delay) * 1000;
	var result = "";

	var x = ms / 1000;
	seconds = x % 60;
	result += seconds.toFixed(0) + "s";
	x = Math.floor(x / 60);
	minutes = x % 60;
	if (x > 0)
		result = "" + minutes.toFixed(0) + "m " + result;
	x = Math.floor(x / 60);
	hours = x % 24;
	if (x > 0)
		result = "" + hours.toFixed(0) + "h " + result;
	x = Math.floor(x / 24);
	days = x;
	if (days > 0)
		result = "" + days.toFixed(0) + "d " + result;

	return result;
}


// get marker html for list
function GetMarkerHtml(marker) {
	return
	$("<li>").html(marker.Name);
	//return marker.Name + marker.Speed;
	//	var info = $("<span>")
	//	$("a").attr("href", "").html(marker.Name + marker.Speed).wrap()
	//	return $("<li>").attr("markerID", marker.ID).append(
	//		$("a").attr("href", "").html(marker.Name + marker.Speed));
	//	//return $("div").html(marker.Name + marker.Speed);
}


// Marker functions=======================================================

//Process markers array
function MarkersRecieved(markers) {
	DeleteUnusedMarkers(markers);

	//Go over the markers recieved from server
	$(markers).each(function() {
		var marker = this;
		var curGMarker = null;
		exists = false;
		var needToRequestNewMarkerImage = false;

		//Go over the gmarkers on page
		$(gMarkers).each(function() {
			var gMarker = this;
			if (gMarker.Marker.ID == marker.ID) {
				exists = true;
				var lastMarkerTime = gMarker.Marker.Delay;
				gMarker.Marker = marker;
				curGMarker = gMarker;

				// check need new marker image
				var currentMarkerTime = gMarker.Marker.Delay;

				// last update after timeToRefreshMarkerImage
				// or last update before timeToRefreshMarkerImage after timeToRefreshMarkerImage
				if ((lastMarkerTime <= timeToRefreshMarkerImage && currentMarkerTime >= timeToRefreshMarkerImage)
					|| (lastMarkerTime >= timeToRefreshMarkerImage && currentMarkerTime <= timeToRefreshMarkerImage)) {
					needToRequestNewMarkerImage = true;
				}
				return;
			}
		});

		if (!exists)//Create new marker
		{
			gMarkers.push(CreateGMarker(marker));
		}
		else//Move existing marker
		{
			curGMarker.setLatLng(new GLatLng(marker.Latitude, marker.Longitude));
			if (needToRequestNewMarkerImage) {
				curGMarker.setImage(urlMarkerImageBase + gameID + "/" + marker.ID + "/" + Math.random() * 100);
			}
		}
	});

	// view all markers first time
	if (firstGetMarkers) {
		firstGetMarkers = false;

		if (gMarkers.length > 0) {
			var latlngbounds = new GLatLngBounds();
			$(gMarkers).each(function() {
				latlngbounds.extend(this.getLatLng());
			});

			// set smart zoom
			var zoomLevel = map.getBoundsZoomLevel(latlngbounds);
			if (zoomLevel > 11)
				zoomLevel = 11;
			// move map
			map.setCenter(latlngbounds.getCenter(), zoomLevel);
		}
	}
}

function DeleteUnusedMarkers(markers) {

	//Go over the markers recieved from server
	for (i = gMarkers.length - 1; i >= 0; i--) {
		var gMarker = gMarkers[i];
		exists = false;

		//Go over the markers on page
		for (j = 0; j < markers.length; j++) {
			if (gMarker.Marker.ID == markers[j].ID) {
				exists = true;
				break;
			}
		}
		if (!exists) {
			deleteMarkerPanel(gMarker.Marker.ID);
			map.removeOverlay(gMarker);
			gMarkers.pop(gMarker);
		}
	}
}

function CreatePointMarket() {
	var baseIcon = new GIcon();
	baseIcon.image = "http://maps.google.com/mapfiles/ms/icons/green-dot.png";
	baseIcon.shadow = "http://maps.google.com/mapfiles/ms/icons/msmarker.shadow.png";
	baseIcon.iconSize = new GSize(32, 32);
	baseIcon.shadowSize = new GSize(59, 32);
	baseIcon.iconAnchor = new GPoint(16, 32);
	baseIcon.infoWindowAnchor = new GPoint(16, 2);
	//baseIcon.infoShadowAnchor = new GPoint(16, 0);

	//create structure of marker parameters
	options = { icon: baseIcon, title: "Указатель", draggable: true, clickable: true };
	//create marker
	pointMarker = new GMarker(map.getCenter(), options);
	map.addOverlay(pointMarker);
	//add event handlers
	//GEvent.addListener(pointMarker, "dragend", function() { ShowPointMarkerInfo() });
	GEvent.addListener(pointMarker, "dragstart", function() { map.closeInfoWindow(); });
	GEvent.addListener(pointMarker, "click", function() { ShowPointMarkerInfo() });
}

function ShowPointMarkerInfo() {
	var info = "<div><b>" + pointMarker.getTitle() + "</b>";
	info += " <a href='#' onclick='HidePointMarker()'>(скрыть)</a><br/>";
	info += "Координаты:" + Number(pointMarker.getLatLng().lat()).toFixed(4) + "," + Number(pointMarker.getLatLng().lng()).toFixed(4)
		+ "<br/><a href='http://www.google.com/maps?f=q&source=s_q&hl=ru&geocode=&q=" + Number(pointMarker.getLatLng().lat()) + "," + Number(pointMarker.getLatLng().lng()) + "&ie=UTF8&z="+map.getZoom()+"' target='_blank'>(ссылка)</a>"
		+ "<br/><br/>"
		+ "<div>Переместить в эту точку маркер:<ul>";

	$(gMarkers).each(function() {
	var onclick = "onclick='onMapGeneratedMarkerClick(" + this.Marker.ID + ", " + pointMarker.getLatLng().lat() + "," + pointMarker.getLatLng().lng() + ")'";
		info += "<li><a href='#'" + onclick + ">" + this.Marker.Name + "<a></li>";
	});

	info += "</ul></div></div>";
	pointMarker.openInfoWindowHtml(info);
}

function HidePointMarker() {
	// close info window
	map.closeInfoWindow();
	pointMarker.hide();
}

function TogglePointMarker() {
	if (pointMarker.isHidden()) {
		pointMarker.setLatLng(map.getCenter());
		pointMarker.show();
	} else {
	if (map.getBounds().containsLatLng(pointMarker.getLatLng()))
		pointMarker.hide();
	else
		pointMarker.setLatLng(map.getCenter());
	}
}

//Create GMarker using marker data 
function CreateGMarker(marker) {
	// Create a base icon for all of our markers that specifies the
	// shadow, icon dimensions, etc.
	var baseIcon = new GIcon();
	baseIcon.image = urlMarkerImageBase + gameID + "/" + marker.ID; // 20x55px
	//baseIcon.image = "http://www.google.com/mapfiles/marker" + letter + ".png";
	baseIcon.shadow = "http://www.google.com/mapfiles/shadow50.png";
	baseIcon.iconSize = new GSize(20, 55);
	baseIcon.shadowSize = new GSize(37, 34);
	baseIcon.iconAnchor = new GPoint(10, 50);
	baseIcon.infoWindowAnchor = new GPoint(10, 20);
	//baseIcon.infoShadowAnchor = new GPoint(18, 80);

	//create structure of marker parameters
	options = { icon: baseIcon, title: marker.Name, draggable: true, clickable: true };
	//create marker
	var gMarker = new GMarker(new GLatLng(marker.Latitude, marker.Longitude), options);
	gMarker.Marker = marker;
	map.addOverlay(gMarker);
	//add event handlers
	GEvent.addListener(gMarker, "dragend", function() { MoveMarker(gMarker) });
	GEvent.addListener(gMarker, "dragstart", function() { map.closeInfoWindow(); });
	GEvent.addListener(gMarker, "click", function() { ShowMarkerInfo(gMarker) });
	return gMarker;
}

//Move marker to current gMarker position
function MoveMarker(gMarker) {
	gMarker.Marker.Latitude = gMarker.getLatLng().lat();
	gMarker.Marker.Longitude = gMarker.getLatLng().lng();
	updateMarkerPanel(findMarkerPanel(gMarker.Marker.ID), gMarker.Marker);
	SetNewMarkerPosition(gMarker.Marker.ID, gMarker.getLatLng().lat(), gMarker.getLatLng().lng());
}

// set new marker position
function SetNewMarkerPosition(markerID, lat, lng) {
	$.post(urlAddPoint, { gameID: gameID, markerID: markerID, lat: lat, lng: lng });
}

//Show HTML info window with information about marker
function ShowMarkerInfo(gMarker) {
	var info = "<b>" + gMarker.Marker.Name + "</b><br/>";
	var signlat = 1;
	var signlon = 1;
	if (gMarker.getLatLng().lng() < 0) { signlon = -1; }
	if (gMarker.getLatLng().lat() < 0) { signlat = -1; }
	var lonAbs = Math.abs(Math.round(gMarker.getLatLng().lng() * 1000000.));
	var latAbs = Math.abs(Math.round(gMarker.getLatLng().lat() * 1000000.));
	var degCoords = ((Math.floor(latAbs / 1000000) * signlat) + '&deg; ' + Math.floor(((latAbs / 1000000) - Math.floor(latAbs / 1000000)) * 60) + '\' ' + (Math.floor(((((latAbs / 1000000) - Math.floor(latAbs / 1000000)) * 60) - Math.floor(((latAbs / 1000000) - Math.floor(latAbs / 1000000)) * 60)) * 100000) * 60 / 100000) + '&quot;')
		+ ", " + ((Math.floor(lonAbs / 1000000) * signlon) + '&deg; ' + Math.floor(((lonAbs / 1000000) - Math.floor(lonAbs / 1000000)) * 60) + '\' ' + (Math.floor(((((lonAbs / 1000000) - Math.floor(lonAbs / 1000000)) * 60) - Math.floor(((lonAbs / 1000000) - Math.floor(lonAbs / 1000000)) * 60)) * 100000) * 60 / 100000) + '&quot;');
	info += "Координаты:" + Number(gMarker.getLatLng().lat()).toFixed(4) + "," + Number(gMarker.getLatLng().lng()).toFixed(4) + "<br/>";
	info += degCoords + "<br/>";
	info += "<a href='http://www.google.com/maps?f=q&source=s_q&hl=ru&geocode=&q=" + Number(gMarker.getLatLng().lat()) + "," + Number(gMarker.getLatLng().lng()) + "&ie=UTF8&z=" + map.getZoom() + "' target='_blank'>(ссылка)</a><br/>";
	info += "Скорость:" + Number(gMarker.Marker.Speed).toFixed(0) + "км/ч<br/>";
	info += "Обновлено:" + GetLastUpdateStringFromDelay(gMarker.Marker.Delay) + "<br/><br/>";
	info += "Трек: <br/>";
	info += " <a href='#' onclick='map.closeInfoWindow();LoadTrack(\"" + gMarker.Marker.Name + " (10 мин)\", \"t_l-600_" + gMarker.Marker.Name + "_app-game.kmz\")'>(загрузить последние 10 мин)</a><br/>";
	info += " <a href='#' onclick='map.closeInfoWindow();LoadTrack(\"" + gMarker.Marker.Name + " (30 мин)\", \"t_l-1800_" + gMarker.Marker.Name + "_app-game.kmz\")'>(загрузить последние 30 мин)</a><br/>";
	info += " <a href='#' onclick='map.closeInfoWindow();LoadTrack(\"" + gMarker.Marker.Name + " (200 точек)\", \"t_p-200_" + gMarker.Marker.Name + "_app-game.kmz\")'>(загрузить последние 200 точек)</a><br/>";
	info += " <a href='#' onclick='map.closeInfoWindow();LoadTrack(\"" + gMarker.Marker.Name + " (500 точек)\", \"t_p-500_" + gMarker.Marker.Name + "_app-game.kmz\")'>(загрузить последние 500 точек)</a><br/>";
	gMarker.openInfoWindowHtml(info);
}

// track functions

// object ID
var loadedTrackLastID = 1;

// Polilyne object
function LoadedTrack(id, overlay) {
	this.ID = id;
	this.Overlay = overlay;
}

// load new track
function LoadTrack(name, urlTrack) {

	// activate tab
	activateTab($("#TrackTab"));

	// id of the object
	var id = loadedTrackLastID++;

	// show UI
	$(".trackresultlist ul").append(
			$("<li>").attr("id", "overlayID" + id).addClass("trackresultlistLI").append(
				$("<div>").addClass("overlayPanel")
			)
		);

	var overlayPanel = $("#overlayID" + id + " div.overlayPanel");

	overlayPanel.append(
			$("<div>").addClass("markerPanelTop").append(
				$("<div>").addClass("markerName").append(
					$("<input>").addClass("overlayInput").attr("type", "checkbox").attr("checked","true")
				).append(
					$("<a>").addClass("overlayNameRef").attr("href", "").append(
						$("<b>").html(name + ' ...')
					)
				).append(
					$("<div>").addClass("markerMenu").append(
						$("<a>").addClass("markerMenuVISIBLE").attr("href", "").html("[X]")
						)
					)
				)
			);

	// attach handlers
	overlayPanel.find("input.overlayInput").live("click", function() {
		if (this.checked)
			ShowTrack(id);
		else
			HideTrack(id);
	});
	overlayPanel.find("a.overlayNameRef").live("click", function() {
		return onOverlayNameClick(overlayPanel.parent());
	});
	overlayPanel.find("a.markerMenuVISIBLE").live("click", function() {
		DeleteTrack(id);
		return false;
	});
	overlayPanel.find("input.overlayInput").hide();

	// request
	$.ajax({
		complete: function() {
			overlayPanel.find("b").html(name + ' ..');
		},
		success: function(result) {
			// create object
			var options = Url.encode(urlTrack);
			var overlay = new GGeoXml(urlGame + "m/" + result + "/" + options, function() {
				if (overlay.loadedCorrectly()) {
					overlayPanel.find("b").html(name);
					overlayPanel.find("input.overlayInput").show();
					overlay.gotoDefaultViewport(map);
				}
				else {
					overlayPanel.find("b").html(name + ' (error loading)');
				}
			});
			loadedTrackArray.push(new LoadedTrack(id, overlay));
			map.addOverlay(overlay);
		},
		url: urlGame + "cl/" + gameID,
		dataType: "json",
		timeout: 30000
	});

	return id;
}

// center track
function onOverlayNameClick(element) {
	var overlayID = element.attr("id");
	$(loadedTrackArray).each(function() {
		if ("overlayID" + this.ID == overlayID) {
			this.Overlay.gotoDefaultViewport(map);
			return;
		}
	});
	return false;
}

// hide track
function HideTrack(idTrack) {
	$(loadedTrackArray).each(function() {
		if (this.ID == Number(idTrack)) {
			this.Overlay.hide();
			return;
		}
	});
}

// show track
function ShowTrack(idTrack) {
	$(loadedTrackArray).each(function() {
		if (this.ID == Number(idTrack)) {
			this.Overlay.show();
			return;
		}
	});
}

// delete track
function DeleteTrack(idTrack) {
	var trackToRemove;
	
	// remove from map
	$(loadedTrackArray).each(function() {
		if (this.ID == Number(idTrack)) {
			map.removeOverlay(this.Overlay);
			trackToRemove = this;
			return;
		}
	});
	
	// remove from array
	loadedTrackArray.pop(trackToRemove);

	// remove from UI
	$("#overlayID" + idTrack).remove();
}

var Url = {

	// public method for url encoding
	encode: function(string) {
		return escape(this._utf8_encode(string));
	},

	// public method for url decoding
	decode: function(string) {
		return this._utf8_decode(unescape(string));
	},

	// private method for UTF-8 encoding
	_utf8_encode: function(string) {
		string = string.replace(/\r\n/g, "\n");
		var utftext = "";

		for (var n = 0; n < string.length; n++) {

			var c = string.charCodeAt(n);

			if (c < 128) {
				utftext += String.fromCharCode(c);
			}
			else if ((c > 127) && (c < 2048)) {
				utftext += String.fromCharCode((c >> 6) | 192);
				utftext += String.fromCharCode((c & 63) | 128);
			}
			else {
				utftext += String.fromCharCode((c >> 12) | 224);
				utftext += String.fromCharCode(((c >> 6) & 63) | 128);
				utftext += String.fromCharCode((c & 63) | 128);
			}

		}

		return utftext;
	},

	// private method for UTF-8 decoding
	_utf8_decode: function(utftext) {
		var string = "";
		var i = 0;
		var c = c1 = c2 = 0;

		while (i < utftext.length) {

			c = utftext.charCodeAt(i);

			if (c < 128) {
				string += String.fromCharCode(c);
				i++;
			}
			else if ((c > 191) && (c < 224)) {
				c2 = utftext.charCodeAt(i + 1);
				string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
				i += 2;
			}
			else {
				c2 = utftext.charCodeAt(i + 1);
				c3 = utftext.charCodeAt(i + 2);
				string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
				i += 3;
			}

		}

		return string;
	}
}